package com.yanqu.road.server.gameplayer.module.activity.flowercard;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.dao.impl.activity.flowercard.UserFlowerCardsDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ValueParamArgs;
import com.yanqu.road.entity.activity.flowercards.*;
import com.yanqu.road.entity.activity.flowercards.config.FlowerCardRoundInfo;
import com.yanqu.road.entity.activity.flowercards.config.FlowerCardScoreInfo;
import com.yanqu.road.entity.activity.flowercards.config.FlowerCardSkillInfo;
import com.yanqu.road.entity.activity.flowercards.enums.eFlowerCardState;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.MallInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.LogFlowerCardEnd;
import com.yanqu.road.entity.log.LogFlowerCardTurnOver;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.activity.FlowerCardsProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.ActivityMallModule;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.flowercard.FlowerCardsConfig;
import com.yanqu.road.server.manger.activity.flowercard.FlowerCardsMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class FlowerCardsModule extends GeneralModule {

    private UserFlowerCardsData userData;

    public FlowerCardsModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = FlowerCardsMgr.getActivityInfo();
        if(ActivityMgr.activityInShowTime(activityInfo)) {
            userData = new UserFlowerCardsDataDaoImpl().getUserFlowerCardsData(activityInfo.getActivityId(), player.getUserId());
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if(userData != null){
            if(userData.isInsertOption()){
                new UserFlowerCardsDataDaoImpl().add(userData);
            }else if(userData.isUpdateOption()){
                new UserFlowerCardsDataDaoImpl().update(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        activityReload();
    }

    public void activityReload() {

        if (!SystemOpenMgr.systemOpen(player, eSystemId.FlowerCards.getValue())) {
            return;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())){
            return;
        }

        syncConfig(config);

        initUserData(config);

        if(!resetOneDay()) {
            syncUserData(config);
        }
    }

    private synchronized void initUserData(FlowerCardsConfig config) {

        if(userData == null || userData.getActivityId() != config.getActivityInfo().getActivityId()){

            UserFlowerCardsData tempData = new UserFlowerCardsData();
            tempData.setUserId(player.getUserId());
            tempData.setActivityId(config.getActivityInfo().getActivityId());
            tempData.setFreeTimes(config.getEnergyResetNum());
            tempData.setCardList(new ArrayList<>());
            tempData.setResetTime(DateHelper.getTodayZeroTime());

            GameStatus status = new GameStatus();
            status.setSettle(true);

            tempData.setGameStatus(status);
            tempData.setInsertOption();

            userData = tempData;

        }

    }

    private void syncUserData(FlowerCardsConfig config) {
        if(userData != null){
            FlowerCardsProto.FlowerCardsUserDataSync.Builder syncBuilder = FlowerCardsProto.FlowerCardsUserDataSync.newBuilder();
            syncBuilder.setUserData(FlowerCardPb.getUserDataBuilder(userData));
            player.sendPacket(Protocol.U_FLOWER_CARDS_SYNC_USER_DATA, syncBuilder);
        }
    }

    private void syncConfig(FlowerCardsConfig config) {

        FlowerCardsProto.FlowerCardsActivityConfigSync.Builder syncBuilder = FlowerCardsProto.FlowerCardsActivityConfigSync.newBuilder();

        for (FlowerCardRoundInfo missionInfo : config.getRoundList()) {
            FlowerCardsProto.FlowerCardsRoundConfigTemp.Builder builder = FlowerCardPb.getMissionBuilder(missionInfo);
            syncBuilder.addRound(builder);
        }

        for (FlowerCardScoreInfo scoreInfo : config.getScoreInfoList()) {
            FlowerCardsProto.FlowerCardsScoreConfigTemp.Builder builder = FlowerCardPb.getScoreBuilder(scoreInfo, player.getLanguage());
            syncBuilder.addScore(builder);
        }

        for (FlowerCardSkillInfo skillInfo : config.getSkillInfoList()) {
            FlowerCardsProto.FlowerCardsSkillConfigTemp.Builder builder = FlowerCardPb.getSkillBuilder(skillInfo, player.getLanguage());
            syncBuilder.addSkill(builder);
        }

        player.sendPacket(Protocol.U_FLOWER_CARDS_SYNC_CONFIG, syncBuilder);
    }

    /**
     * 获取玩家数据
     */
    public int getUserDataReq() {
        if(userData == null){
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        FlowerCardsProto.FlowerCardsUserDataTemp.Builder userBuilder = FlowerCardPb.getUserDataBuilder(userData);
        FlowerCardsProto.FlowerCardsGetUserDataRespMsg.Builder syncBuilder = FlowerCardsProto.FlowerCardsGetUserDataRespMsg.newBuilder();
        syncBuilder.setRet(0);
        syncBuilder.setUserData(userBuilder);
        player.sendPacket(Protocol.U_FLOWER_CARDS_GET_USER_DATA, syncBuilder);
        return 0;
    }

    /**
     * 技能装备
     */
    public int skillLoad(int type) {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        GameStatus gameStatus = userData.getGameStatus();

        int ret = skillLoad(type, config, gameStatus);
        if (ret != 0) {
            return ret;
        }
        userData.setUpdateOption();

        FlowerCardsProto.FlowerCardsSkillLoadRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsSkillLoadRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setUserData(FlowerCardPb.getUserDataBuilder(userData));
        player.sendPacket(Protocol.U_FLOWER_CARDS_SKILL_LOAD, respMsg);

        return 0;
    }

    private int skillLoad(int type, FlowerCardsConfig config, GameStatus gameStatus) {
        if(gameStatus.isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(gameStatus.getSkillSelectList().size() == 0){
            return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
        }

        if(type == 0){

        }else {
            List<FlowerCardFlowerSkill> skillList = gameStatus.getSkillList();
            FlowerCardFlowerSkill skill = null;
            for (FlowerCardFlowerSkill flowerSkill : skillList) {
                if(flowerSkill.getType() == type){
                    skill = flowerSkill;
                }
            }
            if(skill == null){
                FlowerCardSkillInfo skillInfo = config.getFlowerCardSkillInfo(type, 1);
                if(skillInfo == null){
                    return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
                }
                FlowerCardFlowerSkill newSkill = new FlowerCardFlowerSkill();
                newSkill.setLv(1);
                newSkill.setType(type);
                newSkill.setLoadStep(gameStatus.getTotalStep());
                skillList.add(newSkill);
            }else {
                if(config.getFlowerCardSkillInfo(type, skill.getLv() + 1) == null){
                    return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
                }
                skill.setLv(skill.getLv() + 1);
            }
        }

        gameStatus.setSkillSelectList(new ArrayList<>());
        gameStatus.setSkillSelect(false);
        gameStatus.setSelectTimes(0);

        //如果是技能7，npc耐心值上限，则立即生效
        if(type == 7) {
            int skillAddition = FlowerCardsMgr.getSkillAddition(gameStatus, 7, config);
            if (skillAddition > 0) {
                FlowerCardFlowerSkill skill7 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 7);
                if(skill7 != null) {
                    int preLvAddition = FlowerCardsMgr.getSkillAddition(config, 7, skill7.getLv() - 1);
                    skillAddition = skillAddition - preLvAddition;
                }
            }
            if(skillAddition > 0){
                for (FlowerCardBeautyNpc beautyNpc : gameStatus.getBeautyNpcList()) {
                    beautyNpc.setInitPatience(beautyNpc.getInitPatience() + skillAddition);
                    beautyNpc.setPatience(beautyNpc.getInitPatience());
                }
            }
        }
        return 0;
    }

    /**
     * 开始游戏
     */
    public int startGame() {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        if(!userData.getGameStatus().isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_PLAYING;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        //免费次数是否足够
        boolean free = userData.getFreeTimes() > 0;

        //道具是否足够
        Property consume = PropertyHelper.parseStringToProperty(config.getEnergyItemId() + "=" + 1);
        if(!free){
            if(!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.FlowerCardActivity, eLogMoneyType.FlowerCardActivityGameConsume)){
                return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
            }
        }else {
            userData.setFreeTimes(userData.getFreeTimes() - 1);
        }

        //初始行数 列数
        GameStatus tempStatus = new GameStatus();
        //首回合
        tempStatus.setRound(1);
        tempStatus.setStartTime(DateHelper.getCurrentSecond());
        if(!free){
            tempStatus.setUseGoods(true);
        }

        //初始花牌
        List<FlowerCard> cardList = new ArrayList<>();
        List<Integer> beautyIdList = initCardList(config, tempStatus, cardList, 1);

        //初始美女npc
        List<FlowerCardBeautyNpc> beautyNpcList = initBeautyNpcList(config, tempStatus, beautyIdList, 1);
        tempStatus.setBeautyNpcList(beautyNpcList);

        //花露初始化
        FlowerCardRoundInfo roundInfo = config.getFlowerCardRoundInfoById(tempStatus.getRound(), 1);
        if(roundInfo != null){
            tempStatus.setFlowerDew(roundInfo.getStepNum());
        }

        userData.setTotalTimes(userData.getTotalTimes() + 1);
        userData.setCardList(cardList);
        userData.setGameStatus(tempStatus);

        FlowerCardsProto.FlowerCardsStartGameRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsStartGameRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setUserData(FlowerCardPb.getUserDataBuilder(userData));
        player.sendPacket(Protocol.U_FLOWER_CARDS_START_GAME, respMsg);
        return 0;
    }

    /**
     * 初始花牌盘面
     */
    private List<Integer> initCardList(FlowerCardsConfig config, GameStatus tempStatus, List<FlowerCard> cardList, int roundType) {
        //几种美女
        List<Integer> beautyIdList = new ArrayList<>();
        FlowerCardRoundInfo roundInfo = config.getFlowerCardRoundInfoById(tempStatus.getRound(), roundType);
        if(roundInfo == null){
            return beautyIdList;
        }

        //不同美女的数量，与上面对应
        List<Integer> numList = new ArrayList<>(roundInfo.getBeautyNum());
        //美女总数量
        int beautyTotalNum = 0;
        for (int num : numList) {
            beautyTotalNum += num;
        }
        FlowerCardsMgr.setRowCol(tempStatus, beautyTotalNum);

        Random random = new Random();
        int beautyTypeNum = numList.size();
        //美女池 随机
        List<Integer> selectList = new ArrayList<>(roundInfo.getBeautyList());
        while (beautyTypeNum > 0 && selectList.size() > 0){
            beautyIdList.add(selectList.remove(random.nextInt(selectList.size())));
            beautyTypeNum--;
        }

        //最终要出现的美女
        List<Integer> allBeautyList = new ArrayList<>();
        for (int i = 0; i < numList.size(); i++) {
            int num = numList.get(i);
            int beautyId = beautyIdList.get(i);
            for (int k = 0; k < num; k++) {
                allBeautyList.add(beautyId);
            }
        }

        //FlowerCardsMgr.getLogger().info("============  cardList {}", StringUtils.listToString(allBeautyList, "|"));

        //花牌盘面初始
        for (int i = 0; i < beautyTotalNum; i++) {
            int idx = random.nextInt(allBeautyList.size());
            int beautyId = allBeautyList.remove(idx);
            FlowerCard card = new FlowerCard();
            card.setPosition(i);
            card.setCardId(beautyId);
            cardList.add(card);
        }

        return beautyIdList;
    }

    /**
     * 初始npc美女
     */
    private List<FlowerCardBeautyNpc> initBeautyNpcList(FlowerCardsConfig config, GameStatus tempStatus, List<Integer> beautyIdList, int roundType) {
        List<FlowerCardBeautyNpc> result = new ArrayList<>();
        FlowerCardRoundInfo roundInfo = config.getFlowerCardRoundInfoById(tempStatus.getRound(), roundType);
        if(roundInfo == null){
            return result;
        }

        //美女 id
        List<Integer> tempList = new ArrayList<>(beautyIdList);
        //权重
        List<Integer> tempWeightList = new ArrayList<>(roundInfo.getNpcWeights());
        //下标
        List<Integer> indexList = new ArrayList<>();
        for (int i = 0; i < beautyIdList.size(); i++) {
            indexList.add(i);
        }

        Random random = new Random();

        List<Integer> resultBeautyIdList = new ArrayList<>();
        List<Integer> resultIndexList = new ArrayList<>();
        while (tempWeightList.size() > 0){
            int idx = RandomHelper.getRandomIndexByWeight(tempWeightList, random);
            tempWeightList.remove(idx);
            int beautyId = tempList.remove(idx);
            resultBeautyIdList.add(beautyId);
            resultIndexList.add(indexList.remove(idx));
        }

        //技能 黄玫瑰 + 加耐心值
        int skillAddition = FlowerCardsMgr.getSkillAddition(tempStatus, 7, config);
        //战令 + 上限
        int tokenAddition = 0;
        if(userData.getBuyGoldToken() > 0){
            tokenAddition += config.getScoreOrderAdd().get(0);
        }
        if(userData.getBuySliverToken() > 0){
            tokenAddition += config.getSufferanceAdd().get(0);
        }
        //FlowerCardsMgr.getLogger().info("skillAddition 7 :  {}", skillAddition);
        int npcNum = roundInfo.getNpcNum();
        while (npcNum > 0 && resultBeautyIdList.size() > 0){
            int idx = random.nextInt(resultBeautyIdList.size());
            int beautyId = resultBeautyIdList.remove(idx);
            int npcIdx = resultIndexList.remove(idx);
            FlowerCardBeautyNpc npc = new FlowerCardBeautyNpc();
            npc.setBeautyId(beautyId);
            npc.setInitPatience(roundInfo.getNpcSufferance().get(npcIdx) + skillAddition + tokenAddition);
            npc.setPatience(npc.getInitPatience());
            npc.setFlowerDew(roundInfo.getNpcReward().get(npcIdx));
            result.add(npc);
            npcNum--;
        }

        return result;
    }

    /**
     * 翻牌
     */
    public int turnOver(int position) {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        if(userData.getGameStatus().isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(userData.getGameStatus().getFlowerDew() <= 0){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(position < 0 || position > userData.getCardList().size() - 1){
            return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData.getGameStatus().getSkillSelectList().size() > 0){
            return GameErrorCode.E_FLOWER_CARD_NEED_SELECT_SKILL;
        }

        //镜像游戏逻辑数据
        List<FlowerCard> cardList = FlowerCardsMgr.copy(userData.getCardList());
        GameStatus gameStatus = FlowerCardsMgr.copy(userData.getGameStatus());

        List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp = new ArrayList<>();
        GameResult result = turnOver(position, userData, gameStatus, cardList, config, skillTemp, 1);
        if(result.getRet() != 0){
            return result.getRet();
        }

        //奖励
        Property reward = new Property();

        if(result.getState() == 2 || result.getState() == 3){
            //失败  或者 通关

            calSettleReward(config, gameStatus, result, reward);

            gameStatus.setSettle(true);
            if(gameStatus.getAffinity() > userData.getMaxAffinity()){
                userData.setMaxAffinity(gameStatus.getAffinity());
                userData.setMaxAppraise(result.getPingJia());
            }

            if(!reward.isNothing()) {
                player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.FlowerCardActivity, eLogMoneyType.FlowerCardActivityGameOverReward);
            }

            //单局最高积分排行
            player.notifyListener(eGamePlayerEventType.FlowerCardCrossScoreRank.getValue(), new ValueParamArgs(userData.getMaxAffinity(), result.getState() == 2 ? "1" : "0"));

            BigInteger max = BigInteger.valueOf(userData.getMaxAffinity());
            player.notifyListener(eGamePlayerEventType.FlowerCardSliverToken.getValue(), max);
            player.notifyListener(eGamePlayerEventType.FlowerCardBronzeToken.getValue(), max);
            player.notifyListener(eGamePlayerEventType.FlowerCardGoldToken.getValue(), max);
        }else if(result.getState() == 1){
            //下一轮

            //初始花牌
            List<FlowerCard> newCardList = new ArrayList<>();
            List<Integer> beautyIdList = initCardList(config, gameStatus, newCardList, 1);
            cardList = newCardList;

            //初始美女npc
            List<FlowerCardBeautyNpc> beautyNpcList = initBeautyNpcList(config, gameStatus, beautyIdList, 1);
            gameStatus.setBeautyNpcList(beautyNpcList);

            //触发技能选择
            touchSkillSelectList(gameStatus, config, new Random(), 1);
        }

        if(result.getEliminateScore() > 0){
            userData.setTotalAffinity(userData.getTotalAffinity() + result.getEliminateScore());
            //总积分成就
            player.notifyListener(eGamePlayerEventType.FlowerCardScore.getValue(), userData.getTotalAffinity());
        }
        userData.setCardList(cardList);
        userData.setGameStatus(gameStatus);

        gameOverRank(gameStatus);

        FlowerCardsProto.FlowerCardsTurnOverRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsTurnOverRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setPingJia(result.getPingJia());
        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));
        respMsg.setUserData(FlowerCardPb.getUserDataBuilder(userData));
        respMsg.addAllSkill(skillTemp);
        respMsg.setCardId(result.getCardId());
        player.sendPacket(Protocol.U_FLOWER_CARDS_TURN_OVER, respMsg);


        //翻牌日志
        List<FlowerCard> noEliminateList = getFlowerCardsNoEliminate(cardList);
        AutoLogMgr.add(new LogFlowerCardTurnOver(userData.getUserId(),
                userData.getActivityId(),
                //差一轮（可能是上一轮的最后一次消除）
                result.getState() == 1 ? gameStatus.getRound() - 1 : gameStatus.getRound(),
                userData.getTotalTimes(),
                StringUtils.listToString(result.getOpenCardList(), ","),
                StringUtils.listToString(result.getOpenPosList(), ","),
                result.getEliminateCartLis().size(),
                result.getEliminatePosition(),
                noEliminateList.size(),
                result.getEliminateScore(),
                gameStatus.getAffinity(),
                result.getNpcString(),
                result.getGetFlowerDew(),
                gameStatus.getFlowerDew(),
                JSON.toJSONString(gameStatus.getSkillList()),
                gameStatus.getCombo()));

        //结算日志
        if(gameStatus.isSettle()){
            int endType = 0;
            if(result.getState() == 2){
                endType = 1;
            }else if(result.getState() == 3){
                endType = 2;
            }
            AutoLogMgr.add(new LogFlowerCardEnd(userData.getUserId(),
                    userData.getActivityId(),
                    gameStatus.isUseGoods(), gameStatus.getRound(),
                    gameStatus.getAffinity(), gameStatus.getTotalStep(),
                    result.getPingJia(), JSON.toJSONString(gameStatus.getSkillList()),
                    endType, JSON.toJSONString(userData.getCardList()),
                    userData.getTotalTimes(), DateHelper.getCurrentSecond() - gameStatus.getStartTime()));
        }
        return 0;
    }

    private void gameOverRank(GameStatus gameStatus) {
        if (gameStatus.isSettle()) {
            FlowerCardsProto.CrossFlowerCardRankChangeReqMsg.Builder crossReq = FlowerCardsProto.CrossFlowerCardRankChangeReqMsg.newBuilder();
            crossReq.setActivityId(userData.getActivityId());
            crossReq.setConditionType(eGamePlayerEventType.FlowerCardCrossScoreRank.getValue());
            crossReq.setScore(gameStatus.getAffinity());
            player.sendPacket(Protocol.C2_FLOWER_CARD_ACTIVITY_GAME_OVER, crossReq);
        }
    }

    private void calSettleReward(FlowerCardsConfig config, GameStatus gameStatus, GameResult result, Property reward) {
        int maxHighScore = userData.getMaxAffinity();
        if(gameStatus.getAffinity() > maxHighScore){
            maxHighScore = gameStatus.getAffinity();
        }

        Random random = new Random();

        Property pingJiaReward = new Property();
        //评价
        FlowerCardScoreInfo scoreInfo = config.getFlowerCardScoreInfo(gameStatus.getAffinity());
        if(scoreInfo != null){
            result.setPingJia(scoreInfo.getId());
            pingJiaReward = FlowerCardsMgr.getRandomWeightReward(scoreInfo.getRewards(), random);
        }
        reward.addProperty(pingJiaReward);
    }

    /**
     * 刷新技能
     */
    private boolean touchSkillSelectList(GameStatus gameStatus, FlowerCardsConfig config, Random random, int roundType) {
        Set<Integer> hadSkillSet = new HashSet<>();
        Set<Integer> topLvSkillSet = new HashSet<>();
        for (FlowerCardFlowerSkill skill : gameStatus.getSkillList()) {
            hadSkillSet.add(skill.getType());
            if(skill.getLv() == config.getSkillMaxLv(skill.getType())){
                topLvSkillSet.add(skill.getType());
            }
        }

        FlowerCardRoundInfo roundInfo = config.getFlowerCardRoundInfoById(gameStatus.getRound(), roundType);
        if(roundInfo == null){
            return false;
        }

        int needNum = 3;
        List<Integer> poolList = new ArrayList<>(roundInfo.getUnlockSkills());
        //移除满级的技能
        poolList.removeAll(topLvSkillSet);

        //格子未满，允许新技能
        if(hadSkillSet.size() < 3){
            hadSkillSet.clear();
        }else {
            needNum = 3 - topLvSkillSet.size();
        }

        poolList.removeAll(hadSkillSet);
        hadSkillSet.removeAll(topLvSkillSet);

        //FlowerCardsMgr.getLogger().info("====== needNum : {}", needNum);
        while (poolList.size() > 0 && hadSkillSet.size() < needNum){
            int id = poolList.remove(random.nextInt(poolList.size()));
            hadSkillSet.add(id);
        }
        //FlowerCardsMgr.getLogger().info("====== hadSkillSet size : {}", hadSkillSet.size());
        gameStatus.setSkillSelectList(new ArrayList<>(hadSkillSet));
        if(gameStatus.getSkillSelectList().size() > 0) {
            gameStatus.setSkillSelect(true);
            return true;
        }
        return false;
    }

    /**
     * 翻牌逻辑
     */
    private GameResult turnOver(int position, UserFlowerCardsData userData, GameStatus gameStatus, List<FlowerCard> cardList, FlowerCardsConfig config,
                                List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, int roundType) {
        GameResult result = new GameResult(0);

        FlowerCard targetCard = cardList.get(position);
        if(targetCard.getState() != eFlowerCardState.CLOSE.getValue()){
            result.setRet(GameErrorCode.E_FLOWER_CARD_NOT_TURN_OVER);
            return result;
        }
        result.getOpenCardList().add(targetCard.getCardId());
        result.getOpenPosList().add(position);
        result.setCardId(targetCard.getCardId());

        //beforeOpenCard
        beforeOpenCard(gameStatus, cardList);

        Random random = new Random();

        //openCard
        openCard(result, gameStatus, cardList, config, skillTemp, targetCard, random);

        //matchCard
        //消除的卡片
        List<FlowerCard> eliminateCartLis = matchCard(config, gameStatus, cardList, skillTemp, random);
        int eliminateSize = eliminateCartLis.size();

        int loop = 10;
        //配对、消除后技能
        while (afterEliminateCardSkill(result, gameStatus, cardList, config, skillTemp, random, eliminateSize) > 0 && loop > 0){
            List<FlowerCard> tempList = matchCard(config, gameStatus, cardList, skillTemp, random);
            eliminateSize = tempList.size();
            eliminateCartLis.addAll(tempList);
            loop--;
        }

        result.setEliminateCartLis(eliminateCartLis);
        gameStatus.setEfface(gameStatus.getEfface() + eliminateCartLis.size());

        //afterMatchCard
        afterMatchCard(result, gameStatus, eliminateCartLis);

        //连消
        if(eliminateCartLis.size() > 0){
            gameStatus.setCombo(gameStatus.getCombo() + 1);

            //技能加成
            int skillAddition = 0;
            FlowerCardFlowerSkill skill9 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 9);
            if(skill9 != null){
                skillAddition = FlowerCardsMgr.getSkillAddition(config, skill9.getType(), skill9.getLv());
            }
            //战令
            int orderAdd = 0;
            if(userData.getBuyGoldToken() > 0){
                orderAdd += config.getScoreOrderAdd().get(1);
            }
            if(userData.getBuySliverToken() > 0){
                orderAdd += config.getSufferanceAdd().get(1);
            }
            //连消加成
            int comboAddition = 1000;
            if(gameStatus.getCombo() > 0){
                comboAddition = config.getComboAddition(gameStatus.getCombo());
            }
            //消除积分
            int eliminateScore = BigDecimal.valueOf(config.getScoreBase() + orderAdd + skillAddition).multiply(BigDecimal.valueOf(comboAddition)).
                    multiply(BigDecimal.valueOf(eliminateCartLis.size())).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();

            gameStatus.setAffinity(eliminateScore + gameStatus.getAffinity());
            result.setEliminateScore(eliminateScore);
        }

        //closeCard
        int closeSize = closeCard(gameStatus, cardList, config, eliminateCartLis);

        List<FlowerCard> closeCardList = getFlowerCardsClosed(cardList);

        //步数
        boolean stepEnd = gameStatus.getFlowerDew() <= 0;
        //下一轮
        FlowerCardRoundInfo nextRound = config.getFlowerCardRoundInfoById(gameStatus.getRound() + 1, roundType);
        //是否结算、或者下一轮
        if(stepEnd && closeCardList.size() > 0){
            //失败
            result.setState(3);
            return result;
        }else {

            if(closeCardList.size() == 0 && nextRound != null){
                result.setState(1);
                //下一轮
                gameStatus.setRound(gameStatus.getRound() + 1);
                gameStatus.setFlowerDew(gameStatus.getFlowerDew() + nextRound.getStepNum());
                return result;
            }
            if(closeCardList.size() == 0){

                //花露转积分
                int scoreAdd = gameStatus.getFlowerDew() * config.getChangeScore();
                gameStatus.setAffinity(scoreAdd + gameStatus.getAffinity());

                result.setState(2);
                return result;
            }
        }

        //afterCloseCard
        afterCloseCard(gameStatus, config, skillTemp, random, closeSize);

        //lastSkill
        lastSkill(result, gameStatus, cardList, config, skillTemp, random);

        return result;
    }

    private void afterMatchCard(GameResult result, GameStatus gameStatus, List<FlowerCard> eliminateCartLis) {
        //消除美女，是否触发小人赠送花露
        Set<Integer> eliminateIdSet = new HashSet<>();
        for (FlowerCard card : eliminateCartLis) {
            eliminateIdSet.add(card.getCardId());
        }
        if(gameStatus.getBeautyNpcList().size() > 0){
            FlowerCardBeautyNpc npc = gameStatus.getBeautyNpcList().get(0);
            npc.setPatience(npc.getPatience() - 1);
            result.setCurNpc(npc);
            //翻中第一个npc
            if(eliminateIdSet.contains(npc.getBeautyId())){
                gameStatus.setFlowerDew(gameStatus.getFlowerDew() + npc.getFlowerDew());
                gameStatus.getBeautyNpcList().remove(0);
                result.setGetFlowerDew(npc.getFlowerDew());
            }else if(npc.getPatience() <= 0 ){
                gameStatus.getBeautyNpcList().remove(0);
            }
        }
    }

    /**
     * 盖牌之前
     */
    private void beforeOpenCard(GameStatus gameStatus, List<FlowerCard> cardList) {
        //花露减1
        gameStatus.setFlowerDew(gameStatus.getFlowerDew() - 1);
        gameStatus.setTotalStep(gameStatus.getTotalStep() + 1);

        //隐藏透视
        for (FlowerCard flowerCard : cardList) {
            if(flowerCard.isPerspective()){
                if(flowerCard.getPpRound() > 0){
                    flowerCard.setPpRound(flowerCard.getPpRound() - 1);
                }
                if(flowerCard.getPpRound() == 0){
                    flowerCard.setPerspective(false);
                    if(userData.getAlwaysShow() == 1){
                        flowerCard.setShow(true);
                    }
                }
            }
        }
    }

    /**
     * 盖牌
     */
    private int closeCard(GameStatus gameStatus, List<FlowerCard> cardList, FlowerCardsConfig config, List<FlowerCard> eliminateCartLis) {
        //盖牌
        int openNum = FlowerCardsMgr.getSkillAddition(gameStatus, 5, config);
        if(openNum == 0){
            openNum = 2;
        }
        //包括消除的，一起统计
        //int needClose = (gameStatus.getCardOrder().size() + eliminateCartLis.size()) - openNum;
        //去掉消除的，再统计
        int needClose = (gameStatus.getCardOrder().size()) - openNum;
        List<Integer> closeList = new ArrayList<>();
        if(needClose >= 0){
            closeList.addAll(gameStatus.getCardOrder());
            gameStatus.getCardOrder().clear();
        }
        for (int idx : closeList) {
            FlowerCard tempCard = cardList.get(idx);
            if(tempCard.getState() == eFlowerCardState.OPEN.getValue()){
                tempCard.setState(eFlowerCardState.CLOSE.getValue());
            }
        }

        //连续消除
        if(closeList.size() > 0 && eliminateCartLis.size() == 0){
            gameStatus.setCombo(0);
        }
        return closeList.size();
    }

    /**
     * 盖牌之后
     */
    private void afterCloseCard(GameStatus gameStatus, FlowerCardsConfig config, List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, Random random, int closeSize) {
        //盖牌技能
        //赠送玫瑰花
        if(closeSize > 0) {
            FlowerCardFlowerSkill skill8 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 8);
            if (skill8 != null) {
                FlowerCardSkillInfo skillInfo = config.getFlowerCardSkillInfo(skill8.getType(), skill8.getLv());
                if (skillInfo != null) {
                    List<Integer> list = StringUtils.stringToIntegerList(skillInfo.getSkillParam(), "\\|");
                    if (random.nextInt(1000) < list.get(0)) {
                        if (gameStatus.getBeautyNpcList().size() > 0) {
                            FlowerCardBeautyNpc npc = gameStatus.getBeautyNpcList().get(0);
                            npc.setFlowerDew(npc.getFlowerDew() + list.get(1));
                            skillTemp.add(FlowerCardsProto.FlowerCardsSkillDetailTemp.newBuilder().setSkillType(8).build());
                        }
                    }
                }
            }
        }
    }

    /**
     * 翻牌
     */
    private void openCard(GameResult result, GameStatus gameStatus, List<FlowerCard> cardList, FlowerCardsConfig config, List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, FlowerCard targetCard, Random random) {
        //翻牌
        targetCard.setState(eFlowerCardState.OPEN.getValue());
        //targetCard.setPerspective(false);
        targetCard.setPpRound(0);
        targetCard.setShow(userData.getAlwaysShow() == 1);
        gameStatus.getCardOrder().add(targetCard.getPosition());
        //翻牌技能，同时翻开相连的牌
        FlowerCardFlowerSkill skill2 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 2);
        if(skill2 != null){
            int weight = FlowerCardsMgr.getSkillAddition(config, skill2.getType(), skill2.getLv());
            if(random.nextInt(1000) < weight){
                List<Integer> list = FlowerCardsMgr.getFourDirection(targetCard.getPosition(), gameStatus.getRowNum(), gameStatus.getColNum());
                while (list.size() > 0){
                    int pos = list.remove(random.nextInt(list.size()));
                    FlowerCard card = cardList.get(pos);
                    if(card.getState() == eFlowerCardState.CLOSE.getValue()){
                        card.setState(eFlowerCardState.OPEN.getValue());
                        gameStatus.getCardOrder().add(pos);
                        //card.setPerspective(false);
                        card.setShow(userData.getAlwaysShow() == 1);
                        card.setPpRound(0);
                        result.getOpenCardList().add(card.getCardId());
                        result.getOpenPosList().add(pos);
                        FlowerCardsProto.FlowerCardsSkillDetailTemp.Builder builder = FlowerCardsProto.FlowerCardsSkillDetailTemp.newBuilder().setSkillType(2).addPosition(pos).addCardId(card.getCardId());
                        skillTemp.add(builder.build());
                        break;
                    }
                }
            }
        }
    }

    /**
     * 配对、消除
     */
    private List<FlowerCard> matchCard(FlowerCardsConfig config, GameStatus gameStatus, List<FlowerCard> cardList, List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, Random random) {
        //配对、消除
        Map<Integer, List<Integer>> beautyPositionMap = new HashMap<>();
        for (int pos : gameStatus.getCardOrder()) {
            FlowerCard fc = cardList.get(pos);
            beautyPositionMap.putIfAbsent(fc.getCardId(), new ArrayList<>());
            List<Integer> list = beautyPositionMap.get(fc.getCardId());
            list.add(pos);
        }
        List<Integer> eliminateList = new ArrayList<>();
        for (Map.Entry<Integer, List<Integer>> entry : beautyPositionMap.entrySet()) {
            //FlowerCardsMgr.getLogger().info("===== cardId : {}, pos {}", entry.getKey(), StringUtils.listToString(entry.getValue(), ","));
            List<Integer> list = entry.getValue();
            for (int i = 0; i + 1 < list.size(); i = i + 2) {
                eliminateList.add(list.get(i));
                eliminateList.add(list.get(i + 1));
            }
        }
        //eliminateCard
        List<FlowerCard> eliminateCartLis = new ArrayList<>();
        for (Integer pos : eliminateList) {
            FlowerCard card = cardList.get(pos);
            eliminateCartLis.add(card);
            if(card.getState() != eFlowerCardState.ELIMINATE.getValue()){
                card.setState(eFlowerCardState.ELIMINATE.getValue());
            }
        }
        //FlowerCardsMgr.getLogger().info("===== eliminateList pos {}", StringUtils.listToString(eliminateList, ","));
        //移除翻牌顺序
        gameStatus.getCardOrder().removeIf(eliminateList::contains);

        //概率送美女耐心值
        FlowerCardFlowerSkill skill4 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 4);
        if(skill4 != null){
            FlowerCardSkillInfo skillInfo = config.getFlowerCardSkillInfo(skill4.getType(), skill4.getLv());
            List<Integer> paramList = StringUtils.stringToIntegerList(skillInfo.getSkillParam(), "\\|");
            if(random.nextInt(1000) < paramList.get(0)){
                if(gameStatus.getBeautyNpcList().size() > 0) {
                    FlowerCardBeautyNpc npc = gameStatus.getBeautyNpcList().get(0);
                    npc.setPatience(npc.getPatience() + paramList.get(1));
                    skillTemp.add(FlowerCardsProto.FlowerCardsSkillDetailTemp.newBuilder().setSkillType(4).build());
                }
            }
        }

        return eliminateCartLis;
    }

    /**
     * 消除之后(橙玫瑰)
     */
    private int afterEliminateCardSkill(GameResult result, GameStatus gameStatus, List<FlowerCard> cardList, FlowerCardsConfig config, List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, Random random, int eliminateSize) {
        //盘面盖牌信息
        List<FlowerCard> closeCardList = getFlowerCardsClosed(cardList);

        //橙玫瑰
        if(closeCardList.size() > 0 && eliminateSize > 0){
            FlowerCardFlowerSkill skill3 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 3);
            if(skill3 != null){
                int weight = FlowerCardsMgr.getSkillAddition(config, skill3.getType(), skill3.getLv());
                if(random.nextInt(1000) < weight){
                    int idx = random.nextInt(closeCardList.size());
                    FlowerCard card = closeCardList.remove(idx);
                    card.setState(eFlowerCardState.OPEN.getValue());
                    card.setShow(userData.getAlwaysShow() == 1);
                    gameStatus.getCardOrder().add(card.getPosition());
                    card.setPpRound(0);
                    //card.setPerspective(false);
                    result.getOpenCardList().add(card.getCardId());
                    result.getOpenPosList().add(card.getPosition());
                    skillTemp.add(FlowerCardsProto.FlowerCardsSkillDetailTemp.newBuilder().setSkillType(3).addCardId(card.getCardId()).addPosition(card.getPosition()).build());
                    return 1;
                }
            }
        }
        return 0;
    }

    /**
     * 最后技能
     */
    private void lastSkill(GameResult result, GameStatus gameStatus, List<FlowerCard> cardList, FlowerCardsConfig config, List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, Random random) {
        //技能透视
        //粉玫瑰
        List<FlowerCard> toPerspectiveList = getFlowerCardsClosedAndNoPerspective(cardList);
        if(toPerspectiveList.size() > 0){
            FlowerCardFlowerSkill skill1 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 1);
            if(skill1 != null) {
                FlowerCardSkillInfo skillInfo = config.getFlowerCardSkillInfo(skill1.getType(), skill1.getLv());
                if (skillInfo != null) {
                    List<Integer> paramList = StringUtils.stringToIntegerList(skillInfo.getSkillParam(), "\\|");
                    int weight = paramList.get(0);
                    int num = paramList.get(1);
                    int stepNum = paramList.get(2);
                    if(random.nextInt(1000) < weight){
                        FlowerCardsProto.FlowerCardsSkillDetailTemp.Builder builder = FlowerCardsProto.FlowerCardsSkillDetailTemp.newBuilder().setSkillType(1);
                        randomPerspective(skillTemp, random, toPerspectiveList, num, stepNum, builder);
                    }
                }
            }
        }

        //紫玫瑰
        //步数消耗，可以透视
        FlowerCardFlowerSkill skill6 = FlowerCardsMgr.getFlowerCardFlowerSkill(gameStatus, 6);
        if(skill6 != null) {
            FlowerCardSkillInfo skillInfo = config.getFlowerCardSkillInfo(skill6.getType(), skill6.getLv());
            if (skillInfo != null) {
                List<Integer> paramList = StringUtils.stringToIntegerList(skillInfo.getSkillParam(), "\\|");
                toPerspectiveList = getFlowerCardsClosedAndNoPerspective(cardList);
                if(toPerspectiveList.size() > 0){
                    if(result.getGetFlowerDew() > 0){
                        int num = paramList.get(0);
                        int stepNum = paramList.get(1);
                        FlowerCardsProto.FlowerCardsSkillDetailTemp.Builder builder = FlowerCardsProto.FlowerCardsSkillDetailTemp.newBuilder().setSkillType(6);
                        randomPerspective(skillTemp, random, toPerspectiveList, num, stepNum, builder);
                    }
                }
            }
        }
    }

    private void randomPerspective(List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp, Random random, List<FlowerCard> toPerspectiveList, int num, int stepNum, FlowerCardsProto.FlowerCardsSkillDetailTemp.Builder builder) {
        while (num > 0 && toPerspectiveList.size() > 0) {
            FlowerCard card = toPerspectiveList.remove(random.nextInt(toPerspectiveList.size()));
            if(card.isShow()){
                continue;
            }
            card.setPerspective(true);
            card.setPpRound(stepNum);
            builder.addPosition(card.getPosition()).addCardId(card.getCardId());
            num--;
        }
        if (builder.getPositionCount() > 0) {
            skillTemp.add(builder.build());
        }
    }

    private List<FlowerCard> getFlowerCardsClosed(List<FlowerCard> cardList) {
        List<FlowerCard> closeCardList = new ArrayList<>();
        for (FlowerCard card : cardList) {
            if(card.getState() == eFlowerCardState.CLOSE.getValue()){
                closeCardList.add(card);
            }
        }
        return closeCardList;
    }

    private List<FlowerCard> getFlowerCardsClosedAndNoPerspective(List<FlowerCard> cardList) {
        List<FlowerCard> closeCardList = new ArrayList<>();
        for (FlowerCard card : cardList) {
            if(card.getState() == eFlowerCardState.CLOSE.getValue() && !card.isPerspective()){
                closeCardList.add(card);
            }
        }
        return closeCardList;
    }

    private List<FlowerCard> getFlowerCardsNoEliminate(List<FlowerCard> cardList) {
        List<FlowerCard> closeCardList = new ArrayList<>();
        for (FlowerCard card : cardList) {
            if(card.getState() == eFlowerCardState.CLOSE.getValue() || card.getState() == eFlowerCardState.OPEN.getValue()){
                closeCardList.add(card);
            }
        }
        return closeCardList;
    }

    /**
     * 技能重随
     */
    public int skillRefresh() {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        if(userData.getGameStatus().isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(userData.getGameStatus().getSkillSelectList().size() == 0){
            return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        //扣消耗
        List<Integer> consumeList = StringUtils.stringToIntegerList(config.getSkillResetConsume(), "\\|");
        int num = Math.min(consumeList.get(2), consumeList.get(0)  + (userData.getGameStatus().getSelectTimes()) * consumeList.get(1));
        String consume = GameConfig.GAME_MONEY_INGOTS + "=" + num;
        if(!player.getModule(CurrencyModule.class).removeCurrency(PropertyHelper.parseStringToProperty(consume), eLogMoneyType.FlowerCardActivity, eLogMoneyType.FlowerCardActivitySkillRefreshConsume)){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        userData.getGameStatus().setSelectTimes(userData.getGameStatus().getSelectTimes() + 1);
        boolean result = touchSkillSelectList(userData.getGameStatus(), config, new Random(), 1);
        if(result){
            userData.setUpdateOption();
        }

        FlowerCardsProto.FlowerCardsSkillRefreshRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsSkillRefreshRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setSkillSelectTimes(userData.getGameStatus().getSelectTimes());
        for (int id : userData.getGameStatus().getSkillSelectList()) {
            respMsg.addSkillSelect(FlowerCardPb.getFlowerCardsSkillTemp(id, 1));
        }
        player.sendPacket(Protocol.U_FLOWER_CARDS_SKILL_RANDOM, respMsg);
        return 0;
    }

    /**
     * 提前结算
     */
    public int settle() {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        GameStatus gameStatus = userData.getGameStatus();
        if(gameStatus.isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        GameResult result = new GameResult(0);
        Property reward = new Property();
        calSettleReward(config, gameStatus, result, reward);

        gameStatus.setSettle(true);
        userData.setUpdateOption();
        if(gameStatus.getAffinity() > userData.getMaxAffinity()){
            userData.setMaxAffinity(gameStatus.getAffinity());
            userData.setMaxAppraise(result.getPingJia());
        }

        if(!reward.isNothing()) {
            player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.FlowerCardActivity, eLogMoneyType.FlowerCardActivityGameOverReward);
        }

        BigInteger max = BigInteger.valueOf(userData.getMaxAffinity());
        player.notifyListener(eGamePlayerEventType.FlowerCardSliverToken.getValue(), max);
        player.notifyListener(eGamePlayerEventType.FlowerCardBronzeToken.getValue(), max);
        player.notifyListener(eGamePlayerEventType.FlowerCardGoldToken.getValue(), max);

        //单局最高积分排行
        player.notifyListener(eGamePlayerEventType.FlowerCardCrossScoreRank.getValue(), new ValueParamArgs(userData.getMaxAffinity(), "0"));

        gameOverRank(gameStatus);

        FlowerCardsProto.FlowerCardsSettleRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsSettleRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));
        respMsg.setUserData(FlowerCardPb.getUserDataBuilder(userData));
        player.sendPacket(Protocol.U_FLOWER_CARDS_SETTLE, respMsg);

        AutoLogMgr.add(new LogFlowerCardEnd(userData.getUserId(),
                userData.getActivityId(),
                gameStatus.isUseGoods(), gameStatus.getRound(),
                gameStatus.getAffinity(), gameStatus.getTotalStep(),
                result.getPingJia(), JSON.toJSONString(gameStatus.getSkillList()),
                3, JSON.toJSONString(userData.getCardList()),
                userData.getTotalTimes(), DateHelper.getCurrentSecond() - gameStatus.getStartTime()));
        return 0;
    }

    public void rechargeCard(int activityId, MallInfo mallInfo) {
        try {
            if (userData == null) {
                return;
            }
            if (userData.getActivityId() != activityId) {
                return;
            }

            FlowerCardsConfig config = FlowerCardsMgr.getConfig();
            if (config == null) {
                return;
            }

            BigInteger maxAffinity = BigInteger.valueOf(userData.getMaxAffinity());

            int addPatience = 0;
            if(mallInfo.getShopType() == eShopType.ChineseChessSilverToken.getValue()){
                userData.setBuySliverToken(1);
                player.notifyListener(eGamePlayerEventType.FlowerCardSliverToken.getValue(), maxAffinity);
                addPatience = config.getSufferanceAdd().get(0);

                //作弊
                GoodsInfo goodsInfo = GoodsMgr.getGoodsById(eItemId.FlowerCardSilver.getValue());
                if(goodsInfo != null && goodsInfo.getParamList().get(3).intValue() == 1){
                    userData.setAlwaysShow(1);
                }
                for (FlowerCard card : userData.getCardList()) {
                    if(card.getState() == eFlowerCardState.OPEN.getValue()){
                        card.setShow(true);
                    }
                }
            }else if(mallInfo.getShopType() == eShopType.ChineseChessGoldToken.getValue()){
                userData.setBuyGoldToken(1);
                player.notifyListener(eGamePlayerEventType.FlowerCardGoldToken.getValue(), maxAffinity);
                addPatience = config.getScoreOrderAdd().get(0);
                //作弊
                GoodsInfo goodsInfo = GoodsMgr.getGoodsById(eItemId.FlowerCardGold.getValue());
                if(goodsInfo != null && goodsInfo.getParamList().get(3).intValue() == 1){
                    userData.setAlwaysShow(1);
                }
                for (FlowerCard card : userData.getCardList()) {
                    if(card.getState() == eFlowerCardState.OPEN.getValue()){
                        card.setShow(true);
                    }
                }
            }

            //特权，美女耐心值上限
            if(addPatience > 0){
                if(!userData.getGameStatus().isSettle()){
                    for (FlowerCardBeautyNpc npc : userData.getGameStatus().getBeautyNpcList()) {
                        npc.setInitPatience(npc.getInitPatience() + addPatience);
                    }
                    userData.setUpdateOption();
                }
            }
            syncUserData(config);

        }catch (Exception e){
            FlowerCardsMgr.getLogger().error(" {} rechargeCard error, mallId {} ,activityId : {}", player.getUserId(), mallInfo.getMallId(), mallInfo.getActivityId());
        }
    }

    public boolean canPrecharge(MallInfo mallInfo) {
        if(userData == null){
            return false;
        }
        // 没有活动
        if (!ActivityMgr.activityInShowTime(FlowerCardsMgr.getActivityInfo()) || FlowerCardsMgr.getConfig() == null) {
            return false;
        }

        return !player.getModule(ActivityMallModule.class).isOverLimitBuyCount(mallInfo, 1);
    }

    public boolean isBuyToken(int shopType) {
        if(userData == null){
            return false;
        }
        if(shopType == eShopType.ChineseChessGoldToken.getValue()){
            return userData.getBuyGoldToken() > 0;
        }
        if(shopType == eShopType.ChineseChessSilverToken.getValue()){
            return userData.getBuySliverToken() > 0;
        }
        return false;
    }


    public boolean resetOneDay(){

        if(userData == null){
            return false;
        }

        // 没有活动
        if (!ActivityMgr.activityInTime(FlowerCardsMgr.getActivityInfo()) || FlowerCardsMgr.getConfig() == null) {
            return false;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();

        int zeroTime = DateHelper.getTodayZeroTime();
        if(userData.getResetTime() != zeroTime){
            userData.setFreeTimes(config.getEnergyResetNum());
            userData.setResetTime(zeroTime);
            syncUserData(config);
            return true;
        }
        return false;
    }

    //--------------------  练习模式
    public int startGameTest() {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        //初始行数 列数
        GameStatus tempStatus = new GameStatus();
        //首回合
        tempStatus.setRound(1);
        tempStatus.setStartTime(DateHelper.getCurrentSecond());

        //初始花牌
        List<FlowerCard> cardList = new ArrayList<>();
        List<Integer> beautyIdList = initCardList(config, tempStatus, cardList, 0);

        //初始美女npc
        List<FlowerCardBeautyNpc> beautyNpcList = initBeautyNpcList(config, tempStatus, beautyIdList, 0);
        tempStatus.setBeautyNpcList(beautyNpcList);

        //花露初始化
        FlowerCardRoundInfo roundInfo = config.getFlowerCardRoundInfoById(tempStatus.getRound(), 0);
        if(roundInfo != null){
            tempStatus.setFlowerDew(roundInfo.getStepNum());
        }

        //练习模式直接上技能选择
        touchSkillSelectList(tempStatus, config, new Random(), 0);
        if(userData.getTotalAffinity() <= 0){
            //第一个技能强制
            tempStatus.getSkillSelectList().set(0, 9);
        }


        userData.setTestCardList(cardList);
        userData.setTestGameStatus(tempStatus);

        FlowerCardsProto.FlowerCardsStartGameTestRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsStartGameTestRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setTestStatus(FlowerCardPb.getGameStatusBuilder(userData.getTestGameStatus()));
        respMsg.addAllTestCard(FlowerCardPb.getCardListBuilder(userData.getTestCardList()));
        if(userData.getTotalAffinity() == 0){
            for (FlowerCard card : userData.getTestCardList()) {
                respMsg.addCardId(card.getCardId());
            }
        }
        player.sendPacket(Protocol.U_FLOWER_CARDS_START_GAME_TEST, respMsg);

        return 0;
    }

    public int turnOverTest(int position) {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        GameStatus testGameStatus = userData.getTestGameStatus();
        if(testGameStatus.isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(testGameStatus.getFlowerDew() <= 0){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(position < 0 || position > userData.getTestCardList().size() - 1){
            return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
        }

        if(testGameStatus.getSkillSelectList().size() > 0){
            return GameErrorCode.E_FLOWER_CARD_NEED_SELECT_SKILL;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        //镜像游戏逻辑数据
        List<FlowerCard> cardList = FlowerCardsMgr.copy(userData.getTestCardList());
        GameStatus gameStatus = FlowerCardsMgr.copy(userData.getTestGameStatus());

        List<FlowerCardsProto.FlowerCardsSkillDetailTemp> skillTemp = new ArrayList<>();
        GameResult result = turnOver(position, userData, gameStatus, cardList, config, skillTemp, 0);
        if(result.getRet() != 0){
            return result.getRet();
        }

        if(result.getState() == 2 || result.getState() == 3){
            //失败  或者 通关
            gameStatus.setSettle(true);
        }else if(result.getState() == 1){
            //下一轮

            //初始花牌
            List<FlowerCard> newCardList = new ArrayList<>();
            List<Integer> beautyIdList = initCardList(config, gameStatus, newCardList, 0);
            cardList = newCardList;

            //初始美女npc
            List<FlowerCardBeautyNpc> beautyNpcList = initBeautyNpcList(config, gameStatus, beautyIdList, 0);
            gameStatus.setBeautyNpcList(beautyNpcList);

            //触发技能选择
            touchSkillSelectList(gameStatus, config, new Random(), 0);
        }

        userData.setTestCardList(cardList);
        userData.setTestGameStatus(gameStatus);

        FlowerCardsProto.FlowerCardsTurnOverTestRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsTurnOverTestRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setPingJia(result.getPingJia());
        respMsg.setTestStatus(FlowerCardPb.getGameStatusBuilder(userData.getTestGameStatus()));
        respMsg.addAllTestCard(FlowerCardPb.getCardListBuilder(userData.getTestCardList()));
        respMsg.addAllSkill(skillTemp);
        respMsg.setCardId(result.getCardId());
        player.sendPacket(Protocol.U_FLOWER_CARDS_TURN_OVER_TEST, respMsg);

        return 0;
    }

    public int skillLoadTest(int type) {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        GameStatus gameStatus = userData.getTestGameStatus();

        int ret = skillLoad(type, config, gameStatus);
        if (ret != 0) {
            return ret;
        }

        FlowerCardsProto.FlowerCardsSkillLoadTestRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsSkillLoadTestRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setTestStatus(FlowerCardPb.getGameStatusBuilder(userData.getTestGameStatus()));
        respMsg.addAllTestCard(FlowerCardPb.getCardListBuilder(userData.getTestCardList()));
        player.sendPacket(Protocol.U_FLOWER_CARDS_SKILL_LOAD_TEST, respMsg);
        return 0;
    }

    public int skillRefreshTest() {

        if(userData == null){
            return  GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        GameStatus testGameStatus = userData.getTestGameStatus();
        if(testGameStatus.isSettle()){
            return GameErrorCode.E_FLOWER_CARD_GAME_OVER;
        }

        if(testGameStatus.getSkillSelectList().size() == 0){
            return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
        }

        FlowerCardsConfig config = FlowerCardsMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        touchSkillSelectList(testGameStatus, config, new Random(), 0);

        FlowerCardsProto.FlowerCardsSkillRefreshTestRespMsg.Builder respMsg = FlowerCardsProto.FlowerCardsSkillRefreshTestRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setSkillSelectTimes(testGameStatus.getSelectTimes());
        for (int id : testGameStatus.getSkillSelectList()) {
            respMsg.addSkillSelect(FlowerCardPb.getFlowerCardsSkillTemp(id, 1));
        }
        player.sendPacket(Protocol.U_FLOWER_CARDS_SKILL_RANDOM_TEST, respMsg);
        return 0;
    }

    //--------------------  练习模式


    public UserFlowerCardsData getUserData() {
        return userData;
    }
}
